package com.evil.account.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.evil.account.api.RemoteRoleService;
import com.evil.account.mapper.RoleMapper;
import com.evil.account.pojo.entity.Role;
import com.evil.account.service.RoleService;
import com.evil.account.service.UserEnterpriseService;
import com.evil.account.util.RoleCodeUtil;
import com.evil.common.account.dto.role.*;
import com.evil.common.account.util.LoginUtil;
import com.evil.common.core.dto.FindByIdsReqDTO;
import com.evil.common.core.entity.QueryModel;
import com.evil.common.core.enums.RCodeEnum;
import com.evil.common.core.enums.SwitchEnum;
import com.evil.common.core.exception.BusinessException;
import com.evil.common.core.util.StreamUtil;
import com.github.pagehelper.PageInfo;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;

/**
 * 角色表
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
@Slf4j
@RestController
@AllArgsConstructor
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService, RemoteRoleService {

    private final LoginUtil loginUtil;

    private final UserEnterpriseService userEnterpriseService;

    private final AccountLogServiceImpl logService;

    /**
     * 通过角色id查询角色信息
     *
     * @param roleId 角色id
     * @return role
     */
    @Override
    public Optional<Role> isExistById(Long roleId) {
        return this.baseMapper.isExistById(roleId);
    }

    /**
     * 通过角色ids查询角色信息
     *
     * @param findByIdsReqDTO findByIdsReqDTO
     * @return role
     */
    @Override
    public List<Role> findByIds(FindByIdsReqDTO findByIdsReqDTO) {
        return this.baseMapper.findByIds(findByIdsReqDTO.getIds(), findByIdsReqDTO.getFilterDeleted());
    }

    /**
     * 通过角色ids查询角色基础信息
     *
     * @param findByIdsReqDTO findByIdsReqDTO
     * @return role
     */
    @Override
    public List<RoleBaseRespDTO> findBaseByIds(FindByIdsReqDTO findByIdsReqDTO) {
        if (findByIdsReqDTO.getCache()) {
            return this.baseMapper.findBaseByIds_Cache(findByIdsReqDTO.getIds(), findByIdsReqDTO.getFilterDeleted());
        } else {
            return this.baseMapper.findBaseByIds(findByIdsReqDTO.getIds(), findByIdsReqDTO.getFilterDeleted());
        }
    }

    /**
     * 通过角色ids查询角色信息
     *
     * @param findByIdsReqDTO findByIdsReqDTO
     * @return role
     */
    @Override
    public Map<Long, Role> findMapByIds(FindByIdsReqDTO findByIdsReqDTO) {
        return this.baseMapper.findMapByIds(findByIdsReqDTO.getIds(), findByIdsReqDTO.getFilterDeleted());
    }

    /**
     * 通过角色ids查询角色基础信息
     *
     * @param findByIdsReqDTO findByIdsReqDTO
     * @return role
     */
    @Override
    public Map<Long, RoleBaseRespDTO> findBaseMapByIds(FindByIdsReqDTO findByIdsReqDTO) {
        return StreamUtil.toMapK(this.findBaseByIds(findByIdsReqDTO), RoleBaseRespDTO::getRoleId);
    }

    @Override
    public List<RoleBaseRespDTO> roleBases(RolePageReqDTO rolePageReqDTO) {
        rolePageReqDTO.setEnterpriseId(loginUtil.getParamEnterpriseId(rolePageReqDTO.getEnterpriseId()));
        return this.baseMapper.roleBases(rolePageReqDTO);
    }

    /**
     * 新增角色
     *
     * @param addRoleReqDTO addRoleReqDTO
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void add(AddRoleReqDTO addRoleReqDTO) {
        // 检查企业管理员
        userEnterpriseService.checkEnterpriseManager(loginUtil.getLoginUserEnterprise());

        addRoleReqDTO.setEnterpriseId(loginUtil.getParamEnterpriseId(addRoleReqDTO.getEnterpriseId()));

        // 处理角色code
        this.handleRoleCode(addRoleReqDTO);

        Role role = BeanUtil.copyProperties(addRoleReqDTO, Role.class);
        logService.saveAndCheck(this.baseMapper, Role::getRoleId, role);
    }

    /**
     * 编辑角色
     *
     * @param modifyRoleReqDTO modifyRoleReqDTO
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void modify(ModifyRoleReqDTO modifyRoleReqDTO) {
        // 检查企业管理员
        userEnterpriseService.checkEnterpriseManager(loginUtil.getLoginUserEnterprise());

        modifyRoleReqDTO.setEnterpriseId(loginUtil.getParamEnterpriseId(modifyRoleReqDTO.getEnterpriseId()));

        Role role = this.baseMapper.findById(modifyRoleReqDTO.getRoleId());
        // 检查企业
        loginUtil.checkEnterpriseId(role.getEnterpriseId());

        // 处理角色code
        this.handleRoleCode(modifyRoleReqDTO);

        BeanUtil.copyProperties(modifyRoleReqDTO, role);
        logService.saveAndCheck(this.baseMapper, Role::getRoleId, role);
    }

    /**
     * 获取角色列表
     *
     * @param queryModel queryModel
     * @return PageInfo
     */
    @Override
    public PageInfo<RolePageRespDTO> page(QueryModel<RolePageReqDTO> queryModel) {
        RolePageReqDTO param = queryModel.getParam();
        param.setEnterpriseId(loginUtil.getParamEnterpriseId(param.getEnterpriseId()));
        return this.baseMapper.rolePage(queryModel);
    }

    /**
     * 删除角色
     *
     * @param deleteRoleReqDTO deleteRoleReqDTO
     */
    @Override
    public void delete(DeleteRoleReqDTO deleteRoleReqDTO) {
        // 检查企业管理员
        userEnterpriseService.checkEnterpriseManager(loginUtil.getLoginUserEnterprise());
        Role role = this.baseMapper.findById(deleteRoleReqDTO.getRoleId());
        // 检查企业
        loginUtil.checkEnterpriseId(role.getEnterpriseId());

        role.setIsDeleted(SwitchEnum.YES.getId());
        logService.saveAndCheck(this.baseMapper, Role::getRoleId, role);
    }

    @Override
    public void isEnable(EnableRoleReqDTO enableRoleReqDTO) {
        // 检查企业管理员
        userEnterpriseService.checkEnterpriseManager(loginUtil.getLoginUserEnterprise());
        List<Role> roles = this.baseMapper.findByIds(enableRoleReqDTO.getRoleIds(), true);
        if (roles.size() != enableRoleReqDTO.getRoleIds().size()) {
            throw new BusinessException(RCodeEnum.ROLE_NOT_EXIST);
        }
        // 必须同一个企业
        Set<Long> enterpriseIds = StreamUtil.transSetT(roles, Role::getEnterpriseId);
        if (enterpriseIds.size() != 1) {
            throw new BusinessException(RCodeEnum.ACCESS_DENIED);
        }
        // 检查企业
        Long enterpriseId = enterpriseIds.stream().findFirst().orElseThrow(() -> new BusinessException(RCodeEnum.ACCESS_DENIED));
        loginUtil.checkEnterpriseId(enterpriseId);

        roles.forEach(r -> r.setIsEnable(enableRoleReqDTO.getIsEnable()));
        logService.saveBatchAndCheck(this.baseMapper, Role::getRoleId, roles);
    }

    /**
     * 处理角色code
     *
     * @param addRoleReqDTO addRoleReqDTO
     */
    private void handleRoleCode(AddRoleReqDTO addRoleReqDTO) {
        Function<String, Optional<Role>> isExistByEnterpriseRoleCode = c ->
                this.baseMapper.isExistByEnterpriseRoleCode(addRoleReqDTO.getEnterpriseId(), c);

        if (StringUtils.isNotBlank(addRoleReqDTO.getRoleCode())) {
            if (addRoleReqDTO.getRoleCode().length() >= 32) {
                throw new BusinessException(RCodeEnum.PARAMETER_TOO_LONG);
            }
            // 这些严格控制一个角色code在 一个企业中是唯一的；
            Optional<Role> optional = isExistByEnterpriseRoleCode.apply(addRoleReqDTO.getRoleCode());
            optional = optional.filter(r -> {
                if (addRoleReqDTO instanceof ModifyRoleReqDTO) {
                    // 修改角色时，传入的角色code与库一致，该情况不需要报错提示
                    return r.getRoleId().equals(((ModifyRoleReqDTO) addRoleReqDTO).getRoleId());
                }
                return false;
            });
            // 报错提示
            if (optional.isPresent()) {
                throw new BusinessException(RCodeEnum.ROLE_CODE_IS_EXIST);
            }
        } else {
            addRoleReqDTO.setRoleCode(RoleCodeUtil.generateKey(key -> isExistByEnterpriseRoleCode.apply(key).isPresent()));
        }
    }
}
